package com.learning.platform.service;

import com.learning.platform.dto.*;
import com.learning.platform.entity.User;
import com.learning.platform.enums.ErrorCode;
import com.learning.platform.enums.UserRole;
import com.learning.platform.exception.BusinessException;
import com.learning.platform.repository.UserRepository;
import com.learning.platform.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 认证服务类
 * 处理用户注册、登录、刷新令牌、获取和更新用户信息等认证相关操作
 */
@Service
@Transactional
public class AuthService {
    
    private static final Logger logger = LoggerFactory.getLogger(AuthService.class);
    
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;
    
    /**
     * 构造函数，注入依赖
     * @param userRepository 用户数据访问接口
     * @param passwordEncoder 密码加密器
     * @param jwtUtil JWT工具类
     */
    public AuthService(UserRepository userRepository, PasswordEncoder passwordEncoder, JwtUtil jwtUtil) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
        this.jwtUtil = jwtUtil;
    }
    
    /**
     * 用户注册
     * @param request 注册请求参数，包含用户名、邮箱和密码
     * @return 认证响应，包含访问令牌和刷新令牌
     * @throws BusinessException 当用户名或邮箱已存在时抛出
     */
    public AuthResponse register(RegisterRequest request) {
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new BusinessException(ErrorCode.USERNAME_EXISTS);
        }
        
        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new BusinessException(ErrorCode.EMAIL_EXISTS);
        }
        
        // 创建新用户
        String encodedPassword = passwordEncoder.encode(request.getPassword());
        User user = new User(request.getUsername(), request.getEmail(), encodedPassword, UserRole.STUDENT);
        
        user = userRepository.save(user);
        logger.info("用户注册成功: username={}, email={}, id={}", user.getUsername(), user.getEmail(), user.getId());
        
        // 生成token
        String accessToken = jwtUtil.generateAccessToken(user.getId(), user.getUsername(), user.getRole().name());
        String refreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername());
        
        return new AuthResponse(accessToken, refreshToken);
    }
    
    /**
     * 用户登录
     * @param request 登录请求参数，包含用户名和密码
     * @return 认证响应，包含访问令牌和刷新令牌
     * @throws BusinessException 当用户不存在或密码错误时抛出
     */
    public AuthResponse login(LoginRequest request) {
        logger.info("尝试登录用户: {}", request.getUsername());

        // 查找用户
        User user = userRepository.findByUsername(request.getUsername())
                .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));

        logger.info("找到用户: {}, 角色: {}", user.getUsername(), user.getRole());

        // 验证密码
        logger.info("验证密码中...");
        if (!passwordEncoder.matches(request.getPassword(), user.getPasswordHash())) {
            logger.warn("密码验证失败");
            throw new BusinessException(ErrorCode.PASSWORD_ERROR);
        }

        logger.info("密码验证成功");
        logger.info("用户登录成功: username={}, id={}, role={}", user.getUsername(), user.getId(), user.getRole());

        // 生成token
        String accessToken = jwtUtil.generateAccessToken(user.getId(), user.getUsername(), user.getRole().name());
        String refreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername());
        return new AuthResponse(accessToken, refreshToken);
    }
    
    /**
     * 刷新访问令牌
     * @param refreshToken 刷新令牌
     * @return 认证响应，包含新的访问令牌和原刷新令牌
     * @throws BusinessException 当刷新令牌无效或用户不存在时抛出
     */
    public AuthResponse refresh(String refreshToken) {
        if (!jwtUtil.validateToken(refreshToken) || !jwtUtil.isRefreshToken(refreshToken)) {
            throw new BusinessException(ErrorCode.USER_NOT_LOGIN, "刷新token无效");
        }
        
        Long userId = jwtUtil.getUserIdFromToken(refreshToken);
        
        // 验证用户仍然存在
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
        
        // 生成新的访问token
        String newAccessToken = jwtUtil.generateAccessToken(user.getId(), user.getUsername(), user.getRole().name());
        
        return new AuthResponse(newAccessToken, refreshToken);
    }
    
    /**
     * 获取当前用户信息
     * @param userId 用户ID
     * @return 用户信息响应
     * @throws BusinessException 当用户不存在时抛出
     */
    @Transactional(readOnly = true)
    public UserResponse getCurrentUser(Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
        
        return new UserResponse(user.getId(), user.getUsername(), user.getEmail(), 
                               user.getNickname(), user.getAvatarUrl(), user.getBio(), 
                               user.getPhone(), user.getRole(), user.getCreatedAt());
    }
    
    /**
     * 更新用户个人资料
     * @param userId 用户ID
     * @param request 个人资料更新请求参数
     * @return 更新后的用户信息响应
     * @throws BusinessException 当用户不存在时抛出
     */
    public UserResponse updateProfile(Long userId, UpdateProfileRequest request) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
        
        // 更新字段
        if (request.getNickname() != null) {
            user.setNickname(request.getNickname());
        }
        if (request.getAvatarUrl() != null) {
            user.setAvatarUrl(request.getAvatarUrl());
        }
        if (request.getBio() != null) {
            user.setBio(request.getBio());
        }
        if (request.getPhone() != null) {
            user.setPhone(request.getPhone());
        }
        
        user = userRepository.save(user);
        logger.info("用户资料更新成功: userId={}, username={}", user.getId(), user.getUsername());
        
        return new UserResponse(user.getId(), user.getUsername(), user.getEmail(), 
                               user.getNickname(), user.getAvatarUrl(), user.getBio(), 
                               user.getPhone(), user.getRole(), user.getCreatedAt());
    }
    
    /**
     * 修改用户密码
     * @param userId 用户ID
     * @param request 密码修改请求参数，包含当前密码和新密码
     * @throws BusinessException 当用户不存在或当前密码不正确时抛出
     */
    public void changePassword(Long userId, ChangePasswordRequest request) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
        
        // 验证当前密码
        if (!passwordEncoder.matches(request.getCurrentPassword(), user.getPasswordHash())) {
            throw new BusinessException(ErrorCode.PASSWORD_ERROR, "当前密码不正确");
        }
        
        // 设置新密码
        String newPasswordHash = passwordEncoder.encode(request.getNewPassword());
        user.setPasswordHash(newPasswordHash);
        
        userRepository.save(user);
        logger.info("用户密码修改成功: userId={}, username={}", user.getId(), user.getUsername());
    }
}
